extends Node

# This class is the main framework controller 
# Responsible of set/get games data in addition to 
# providing the Game UI with the necessary Data for it
# to display
# A framework client means the game that will implements the framework

#signals
signal level_completed
#enums

#constants
var main_thread : Thread = Thread.new()

#public
var home_ui_scn : PackedScene
var lvl_win_scn : PackedScene
var lvl_lose_scn : PackedScene
var skins_scn : PackedScene
var gift_scn : PackedScene
var game_scn : PackedScene
var ads_scn : PackedScene setget _set_ads_scn 
var pop_notif_scn : PackedScene setget _set_notification
var gdpr_scn : PackedScene

var is_new_user : bool
var is_ads_active : bool

var b4d_ads : AdMob
var pop_notif : PopNotification
var game : Node # Main Game

#private
var _level := 1 setget _set_level, _get_level
var _skin := 1 setget _set_skin, _get_skin
var _coins_count := 50 setget set_coins_count , _get_coins_count
var _skins_purchased := [1,] setget set_skins_purchased , get_skins_purchased
var _skins_textures : Dictionary setget set_skins_textures
var _coin_texture : Texture setget set_coin_texture, get_coin_texture
var _game_data : Dictionary = {}  setget set_game_data , get_game_data

#settings
var _settings := {
	"sound" : true,
	"music" : true,
} setget set_settings , get_settings

func _enter_tree() -> void:
	OS.set_window_always_on_top(true)
	is_ads_active = Engine.has_singleton("GodotAdMob") 

# public non-builtin methods



# Game is loaded and ready
func on_game_ready():
	Utils.debug("on_game_ready",1,"Level Start")
	_set_home_ui()



func get_level() -> int:
	return _get_level()


# Internal use only / not exposed to the game
func set_level(value : int) -> void:
	_set_level(value)


func get_skin() -> int:
	return _get_skin()


func set_skin(value) -> void:
	_set_skin(value)


func get_skins_textures() -> Array:
	return _skins_textures.values()


#settings

func get_settings() -> Dictionary:
	return _settings


func set_settings(value : Dictionary):
	_settings = value


func set_game_data(value : Dictionary) -> void:
	_game_data = value


func get_game_data() -> Dictionary:
	return _game_data


# Return a random locked skin
func get_rand_locked_skin() -> int:
	var locked_skins := []
	var unlocked_skins : Array = get_skins_purchased()
	
	var i := 1
	while i <= 6:
		if  not i in unlocked_skins:
			locked_skins.append(i)
		i += 1
	
	if locked_skins.size() == 0 : # all skins are unlocked
		return 0
	else:
		var random = RandomNumberGenerator.new()
		random.randomize()
		return locked_skins[random.randi_range(0,locked_skins.size() - 1)]


func on_level_completed(level_success : bool, data : Dictionary = {}):
	if level_success: # Used by framework client
		_level += 1
	emit_signal("level_completed")
	_level_completed_scene(level_success, data)




# Must be an array of textures
# @example : {0:preload("texture_path"}
func set_skins_textures(textures_array : Dictionary):
	var values := textures_array.values()
	for i in values.size():
		var skin_text  = values[i]
		if skin_text.get_class() != "StreamTexture":
			Utils.debug("_set_skins_textures", 0, "MUST BE ARRAY OF TEXTURES")
			pass
		assert(skin_text.get_class() == "StreamTexture")
		
	_skins_textures = textures_array


# Coin texture used to define the coin used in the game
# coins / star / gems 
# a texture of the game currency must be provided to be used in the UI
func set_coin_texture(texture : Texture) -> void:
	assert(texture.get_class() == "StreamTexture")
	_coin_texture = texture


func get_coin_texture() -> Texture:
	return _coin_texture


func set_skins_purchased(value : Array) -> void:
	_skins_purchased = value


func get_skins_purchased() -> Array:
	return _skins_purchased


func set_coins_count(value : int) -> void:
	_coins_count = value


func get_coins_count() -> int:
	return _get_coins_count()


# settings (sound - music )

# Turn on or off game background music
func set_music(active : bool) -> void:
	if not game.has_method("set_music") :
		Utils.debug("_set_music" , 0 , "set_music Method is not implemented")
		return
	game.set_music(active)
	UserData.update_settings(get_settings().sound,active)


# Turn on or off game sound effect SFX
func set_sound(active : bool) -> void:
	if not game.has_method("set_sound") :
		Utils.debug("_set_sound" , 0 , "set_sound Method is not implemented")
		return
	game.set_sound(active)
	UserData.update_settings(active,get_settings().music)

# Private methods


func _set_level(value : int):
	_level = value


func _get_level() -> int:
	return _level


func _set_skin(value : int):
	_skin = value


func _get_skin() -> int:
	return _skin


func _get_coins_count() -> int:
	return _coins_count


func _level_completed_scene(level_success : bool, data : Dictionary = {}) -> void:
	if level_success:
		var is_gift = (get_level() - 1) % 5 == 0  and is_ads_active # Gift Every X = 5 levels
		if is_gift:
			_show_gift(data.stars)
			return
		
		var level_win : LevelWin = lvl_win_scn.instance()
		game.add_child(level_win)
		level_win.init(data.stars,get_coin_texture())

	else:
		var lvl_lose : LevelLose = lvl_lose_scn.instance()
		game.add_child(lvl_lose)
		lvl_lose.init(data.stars,get_coin_texture())




func _show_gift(earnings : int ) -> void:
	var gift : Gift = gift_scn.instance()
	game.add_child(gift)
	gift.init(earnings)


func _set_ads_scn(value) -> void:
	ads_scn = value
	b4d_ads = ads_scn.instance()
	add_child(b4d_ads)


func _set_notification(value) -> void:
	pop_notif_scn = value
	pop_notif = pop_notif_scn.instance()
	add_child(pop_notif)
	Utils.debug("_set_notification",1,"Set")


func _set_home_ui() -> void:
	var home_ui : HomeUI = home_ui_scn.instance()
	game = get_tree().get_current_scene()
	
	game.add_child(home_ui)
	home_ui.init(get_coins_count(),get_level(),get_coin_texture(),get_skin())
